use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use crate::get_constant_info_from_vm_class;
use crate::instruction::instruction::Instruction;
use crate::class::vm_access_flags::{is_final, is_static};
use crate::class::vm_class_constant_info::VMClassConstantInfoEnum;
use crate::vm_thread::{VMFrame, VMThread};
use crate::vm_val::{FALSE, TRUE, VMValChar, VMValEnum};

pub struct putstatic {
    pub index: u16,
}

impl Instruction for putstatic {
    fn read_operands(&mut self, frame: Rc<RefCell<VMFrame>>) {
        self.index = frame.borrow_mut().read_u16();
    }

    fn exec(&mut self, frame: Rc<RefCell<VMFrame>>, thread: &VMThread) {
        let mut field_ref = {
            let ro_frame = frame.borrow();
            get_constant_info_from_vm_class!(
            ro_frame.current_vm_class, self.index, VMClassConstantInfoFieldRef)
        };

        field_ref.init(thread);

        let field = field_ref.vm_class_field.clone().unwrap();
        let ro_field = field.borrow();
        if !is_static(ro_field.access_flags) {
            panic!("非静态变量，不允许执行此指令")
        }
        if is_final(ro_field.access_flags) {
            let current_method = frame.borrow().method.clone();
            if current_method.name != "<clinit>" {
                panic!("不允许修改static final类型字段");
            }
        }

        let rw_frame = frame.deref().borrow_mut();
        let mut operand_stack = rw_frame.operand_stack.borrow_mut();
        let field_val = {
            let option_val = operand_stack.pop();
            if option_val.is_none() {
                panic!("操作数栈为空");
            }
            option_val.unwrap()
        };
        let vm_class = field_ref.vm_class.clone().unwrap();
        let mut statis_slot = vm_class.static_slot.borrow_mut();
        // statis_slot.insert(ro_field.slot_id, val);

        match ro_field.descriptor.as_str() {
            "Z" => {
                match field_val {
                    VMValEnum::VMValInteger { val } => {
                        if val.num == 0 {
                            statis_slot.insert(ro_field.slot_id as i32, VMValEnum::VMValBoolean { val: FALSE });
                        } else {
                            statis_slot.insert(ro_field.slot_id as i32, VMValEnum::VMValBoolean { val: TRUE });
                        }
                    }
                    _ => {
                        panic!("类型异常");
                    }
                }
            }
            "C" => {
                match field_val {
                    VMValEnum::VMValShort { val } => {
                        statis_slot.insert(ro_field.slot_id as i32, VMValEnum::VMValChar {
                            val: VMValChar {
                                val: val.num as u16
                            }
                        });
                    }
                    _ => {
                        panic!("类型异常");
                    }
                }
            }
            _ => {
                statis_slot.insert(ro_field.slot_id as i32, field_val);
            }
        }
    }

    fn to_string(&self) -> String {
        String::from("putstatic")
    }
}